﻿using System.Collections.Generic;
using System.Linq;
using Gumini.JulaDB.DataTypes;
using Gumini.JulaDB.Enums;
using Gumini.JulaDB.Provider;
using System;

namespace Gumini.JulaDB.Expressions
{
    /// <summary>
    /// Represents a leaf in the expression tree. This is variable, referring to a column.
    /// Should be in one of the following 2 formats:
    /// [TableName].[ColumnName]
    /// [ColumnName]
    /// </summary>
    internal class Variable : Expression
    {
        public Variable(string identifier)
            : base()
        {
            this.Identifier = identifier;

            var nameParts = identifier.Split('.');
            switch (nameParts.Length)
            {
                case 1:
                    this.TableName = null;
                    this.ColumnName = nameParts[0];
                    break;
                case 2:
                    this.TableName = nameParts[0];
                    this.ColumnName = nameParts[1];
                    break;
                default:
                    throw new JulaDbException(ErrorCode.InvalidIdentifier, "Identifier '{0}' is invalid.", identifier);
            }
        }

        public Variable(string tableName, string columnName)
        {
            this.TableName = tableName;
            this.ColumnName = columnName;
            this.Identifier = String.Format("{0}.{1}", tableName, columnName);
        }

        /// <summary>
        /// Full variable name.
        /// </summary>
        public string Identifier { get; private set; }

        /// <summary>
        /// Name of the table or the table alias. First part of the variable name '[TableName].[ColumnName]'.
        /// Can be null.
        /// </summary>
        public string TableName { get; private set; }

        /// <summary>
        /// Name of the column. Second part of the variable name '[TableName].[ColumnName]'.
        /// </summary>
        public string ColumnName { get; private set; }
    
        public override DataType InferType(Context<DataType> context)
        {
            return context[this.Identifier];
        }

        public override TypedValue Evaluate(List<Context<TypedValue>> context)
        {
            return context.Single()[this.Identifier];
        }

        public override bool Equals(Expression other)
        {
            var b = other as Variable;
            if (b == null)
                return false;
            return
                this.Identifier == b.Identifier;
        }

        public override string ToString()
        {
            return this.Identifier;
        }
    }
}
